import crypto from 'crypto';
import jwt from 'jsonwebtoken';
import dayjs from 'dayjs';
import {
  filter, reverse, find, get, map, keyBy, last
} from 'lodash';
import { getSequelize } from '../db';

export function tonull(value) {
  return value === '' ? null : value;
}

/**
 * 同步加密密码的函数
 * @param {string} password 明文密码
 * @param {string} salt 盐
 * @returns {string} 密文
 */
export function encryptPasswordSync(password, salt) {
  // 创建密码哈希对象
  const hash = crypto.createHash('sha256');

  // 将密码和盐混合，并计算哈希值
  const hashedPassword = hash.update(password + salt).digest('hex');

  return hashedPassword;
}

export const jwtSecret = 'https://www.9-cloud.com.cn';

export function signToken(token, options) {
  if (!options) {
    options = { expiresIn: '24h' };
  }

  return jwt.sign(token, jwtSecret, options);
}

export function today() {
  return dayjs().format('YYYY-MM-DD');
}

/**
 * 获取权限树
 * @param {Array} tree 结果树
 * @param {Array} routers 权限列表
 * @param {Number} parent_code 父亲menu code
 */
export function generatePermissionTree(tree, routers, parent_code) {
  Object.assign(tree, filter(routers, { parent_code }));
  // console.log(tree);

  for (const item of tree) {
    item.children = [];
    generatePermissionTree(item.children, routers, item.code);
  }
}

export function getToday() {
  return dayjs().format('YYYY-MM-DD');
}

export function string2bool(str) {
  if (str === 'Y') {
    return true;
  }

  if (str === 'N') {
    return false;
  }

  return undefined;
}

// 超过1小时
export function over1hour(datetime) {
  return dayjs().diff(dayjs(datetime), 'seconds') > 3600;
}

/**
 * 16进制8位UID转10位10进制
 * @param {*} uid
 */
export function uid2number(uid) {
  const tables = [[0, 0], [0, 0], [0, 0], [0, 0]];
  for (let i = 0; i < 4; i += 1) {
    for (let j = 0; j < 2; j += 1) {
      tables[i][j] = uid[2 * i + j];
    }
  }

  let data = reverse(tables.map((e) => e.join('')));
  return (`0000000000${parseInt(data.join(''), 16)}`).slice(-10);
}

/**
 * 格式化数字
 * @param {Number} number
 * @param {Object} options
 * @returns {string}
 */
export function formatNumber(number, options) {
  if (!options) {
    options = {
      minimumFractionDigits: 2,
      maximumFractionDigits: 2
    };
  }
  return Number.isNaN(Number(number)) ? number : Number(number).toLocaleString('en-US', options);
}

/**
 * 转数字
 * @param {*} num
 * @returns
 */
export function toNumber(num) {
  return isNaN(Number(num)) ? 0 : Number(Number(num).toFixed(2));
}

export function generateOutTradeNo() {
  return dayjs().format('YYYYMMDDHHmmssSSS') + Math.ceil(Math.random() * 10000000000).toString();
}

export const WxPrepayPaidStatus = {
  Waiting: 'Waiting',
  Terminated: 'Terminated',
  Success: 'Success'
};

export function getPrimaryConfirmNumber(reservations) {
  if (reservations.length === 1) {
    return reservations[0].confirmNumber;
  } if (reservations.length > 1) {
    return get(find(reservations[0].ShareReservationDetails, { primary: 'Y' }), 'confirmNumber');
  }

  return null;
}

export function getPrimaryResvNameId(reservations) {
  if (reservations.length === 1) {
    return reservations[0].resvNameId;
  } if (reservations.length > 1) {
    return get(find(reservations[0].ShareReservationDetails, { primary: 'Y' }), 'resvNameId');
  }

  return null;
}

export function getReservationIds(reservation) {
  if (!reservation) {
    return {
      confirm_number: null,
      resv_name_id: null,
      primary_confirm_number: null,
      primary_resv_name_id: null
    };
  }

  if (!reservation.ShareReservationDetails || !Array.isArray(reservation.ShareReservationDetails) || reservation.ShareReservationDetails.length <= 1) {
    return {
      confirm_number: get(reservation, 'confirmNumber', null),
      resv_name_id: get(reservation, 'resvNameId', null),
      primary_confirm_number: get(reservation, 'confirmNumber', null),
      primary_resv_name_id: get(reservation, 'resvNameId', null)
    };
  }
  const confirm_numbers = map(reservation.ShareReservationDetails, 'confirmNumber');
  const resv_name_ids = map(reservation.ShareReservationDetails, 'resvNameId');
  const primaryShare = find(reservation.ShareReservationDetails, { primary: 'Y' });
  return {
    confirm_number: confirm_numbers.join(','),
    resv_name_id: resv_name_ids.join(','),
    primary_confirm_number: get(primaryShare, 'confirmNumber', reservation.confirmNumber),
    primary_resv_name_id: get(primaryShare, 'resvNameId', reservation.resvNameId)
  };
}

export async function getHotelParameters(hotel) {
  const parameters = await getSequelize().models.AppParameterValues.findAll({
    where: { hotel_id: hotel.id },
    raw: true
  });

  const keyParams = keyBy(parameters, 'app_parameter_name_id');
  for (const key in keyParams) {
    keyParams[key] = keyParams[key].app_parameter_value;
  }

  return keyParams;
}

export async function getHotelParametersByHotelId(hotel_id) {
  return getHotelParameters({ id: hotel_id });
}

export async function getHotel(req) {
  /// // for production  ///////
  let { hotelcode, appid } = req.headers;

  if (!hotelcode && !appid) {
    throw new Error('无效的URL链接');
  }

  if (hotelcode === 'LOCALHOST') {
    hotelcode = 'LKHG';
  }

  let hotel;
  if (appid) {
    hotel = await getSequelize().models.Hotels.findOne({ where: { appid } });
  }
  else if (hotelcode) {
    hotel = await getSequelize().models.Hotels.findOne({ where: { code: hotelcode } });
  }

  if (!hotel) {
    throw new Error('无效的URL链接CODE');
  }

  return hotel;
}

export function getSmsParamValue(key, reservation, hotel, url) {
  if (key === 'name') {
    return reservation.lastName;
  } if (key === 'nickname') {
    return hotel.display_name;
  } if (key === 'code') {
    return last(url.split('/'));
  }
}

export function formatLocalError(msg) {
  let message = msg;
  if (!message) {
    message = '未知错误, 编号003';
  }

  if (typeof message === 'object') {
    message = JSON.stringify(msg);
  }

  if (message.indexOf('NO RECORDS FOUND') >= 0) {
    message = '抱歉！目前没有可选房间，您可以稍后再试或到店后在前台办理入住。';
  }
  else if (message.indexOf('BOOKING_NOT_FOUND') >= 0) {
    message = '抱歉！未查询到预订，请检查确认号是否输入正确或咨询酒店前台。';
  }

  return message;
}
